/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/naming-convention */
/* eslint-disable @alipay/auto-lint/named-use-ref */
import { useRef, useCallback, useContext, useMemo, useState } from "react";
import { shallow } from ".";
import { RuleTreeContext } from "../core/RuleTreeContext";
import { Form } from "antd";
import { getLocaleMap } from "../locale";

export function useLatest<T>(value: T) {
  const ref = useRef(value);
  ref.current = value;

  return ref;
}

export function useDebounceFn<T extends (...args: any[]) => void>(
  fn: T,
  delay: number
) {
  const timeoutIdRef = useRef<number | undefined>(null);

  const debouncedFn = useCallback(
    (...args: any[]) => {
      if (timeoutIdRef.current) {
        clearTimeout(timeoutIdRef.current);
      }
      timeoutIdRef.current = window.setTimeout(() => {
        fn(...args);
      }, delay);
    },
    [fn, delay]
  );

  return debouncedFn as T;
}

export function useRefCallback<T extends ((...args: any[]) => any) | undefined>(
  fn: T
): T {
  const fnRef = useRef(fn);
  fnRef.current = fn;

  const wrapFn = useCallback((...args: any[]) => {
    return fnRef.current?.(...args);
  }, []) as T;

  return typeof fn === "function" ? wrapFn : fn;
}

export function useShallow<S, U>(selector: (state: S) => U): (state: S) => U {
  const prev = useRef<U>(null);

  return (state) => {
    const next = selector(state);
    return shallow(prev.current, next)
      ? (prev.current as U)
      : (prev.current = next);
  };
}

export function useOutterComponents() {
  const components = useContext(RuleTreeContext).__components;
  const _Form = components?.Form || Form;
  const _ProForm = components?.ProForm;
  return {
    Form: (_ProForm || _Form) as typeof Form,
    FormList: _Form.List,
    isProForm: !!_ProForm,
  };
}

export function useLocale() {
  const { locale: _locale } = useContext(RuleTreeContext);
  const locale = _locale || "zh-CN";

  const localeMap = useMemo(() => {
    return getLocaleMap(locale);
  }, [locale]);

  return {
    locale,
    localeMap,
  };
}

/**
 * 为react-dnd 拖拽设置根节点，解决与原生h5 dragable冲突问题
 * 问题描述见：https://github.com/react-dnd/react-dnd/issues/3344
 * */
export function useDragRootElement() {
  const [rootElement, setRootElement] = useState<HTMLDivElement>(null!);
  const loadRootElement = useCallback(
    (node: HTMLDivElement) => setRootElement(node),
    []
  );
  return { rootElement, loadRootElement };
}
